package com.alibaba.citrus.cr.mn.order.center.facade.function.impl;

import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.RepositoryInvoker;
import com.alibaba.citrus.cr.common.constant.OrderFeaturesKey;
import com.alibaba.citrus.cr.common.enums.ordercenter.FulfillmentStatusEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.OrderCategoryEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.SalesOrderStatusEnum;
import com.alibaba.citrus.cr.mn.order.center.common.SetOrderTag;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.function.check.AbstractOrderParamsCheckService;
import com.alibaba.citrus.cr.mn.order.center.facade.function.check.SalesOrderUpdateParamsCheck;
import com.alibaba.citrus.cr.mn.order.center.facade.function.common.AbstractOrderAtomUpdateService;
import com.alibaba.citrus.cr.mn.order.center.facade.function.common.SendMsgService;
import com.alibaba.citrus.cr.mn.order.center.facade.function.convert.OrderAtomUpdateRequestToOrderConvert;
import com.alibaba.citrus.cr.mn.order.center.facade.function.convert.OrderLineAtomUpdateRequestToOrderLineConvert;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.DeleteByIdsRequest;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.DeleteByMainIdRequest;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.UpdateOrderLineResponse;
import com.epoch.app.crb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.crb2btradecenter.domain.orderline.service.OrderLineService;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomUpdateRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomUpdateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomCreateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomUpdateRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author zhoubc
 * @date 2023/5/21 17:17
 */
@Service("salesOrderAtomUpdateService")
public class SalesOrderAtomUpdateServiceImpl extends AbstractOrderAtomUpdateService {
    private static final Log log = Log.getLogger(SalesOrderAtomUpdateServiceImpl.class);
    @Resource
    private SalesOrderUpdateParamsCheck salesOrderUpdateParamsCheck;

    @Resource
    private OrderLineAtomUpdateRequestToOrderLineConvert orderLineAtomUpdateRequestToOrderLineConvert;

    @Resource
    private OrderService orderService;

    @Resource
    private OrderLineService orderLineService;

    @Resource
    private OrderAtomUpdateRequestToOrderConvert orderAtomUpdateRequestToOrderConvert;

    @Resource
    private SendMsgService sendMsgService;

    @Override
    public String getOrderTag() {
        return SetOrderTag.NORMAL;
    }

    @Override
    public AbstractOrderParamsCheckService getCheckService() {
        return salesOrderUpdateParamsCheck;
    }

    @Override
    @EpochTransactional(appCode = "cr_b2b_trade_center", dataSourceCode = "cr_ots", dataSourceType = "app")
    @RepositoryInvoker(printLog = false)
    public void submitSaveTransactionalNew(OrderAtomUpdateRequest request, OrderAtomUpdateResponse response) {
        log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew request={} response={}", JSON.toJSONString(request), JSON.toJSONString(response));
        // 查询订单信息
        response.setSalesOrderNo(request.getSalesOrderNo());
        Order dbOrder = queryOrder(request, request.getSalesOrderNo());
        log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew dbOrder={}", JSON.toJSONString(dbOrder));
        if (Objects.isNull(dbOrder)) {
            response.setErrorCode("OC-01-001-01-16-016");
            response.setMessage("订单不存在");
            return;
        }
        // 查询订单明细
        List<OrderLine> dbOderLines = queryOrderLines(dbOrder.getId());
        log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew dbOderLines={}", JSON.toJSONString(dbOderLines));
        // 校验订单状态
        boolean isSuccess = checkOrder(dbOrder, dbOderLines, request, response);
        if (!isSuccess) {
            // 校验失败直接返回
            return;
        }
        // 拼接外部单号，发sap要用
        request.setOutOrderNo(dbOrder.getOuterOrderId());

        List<OrderLine> orderLinesForAdd = new ArrayList<>();
        List<OrderLine> orderLinesForUpdate = new ArrayList<>();
        AtomicInteger currentMaxLineNum = new AtomicInteger();
        // 缓存订单行
        Map<String, OrderLine> orderLineSDOMap = new HashMap<>();
        for (OrderLine dbOrderLine : dbOderLines) {
            if (StringUtils.isNotBlank(dbOrderLine.getSerialNumber())) {
                currentMaxLineNum.set(Math.max(Integer.parseInt(dbOrderLine.getSerialNumber()), currentMaxLineNum.get()));
            }
            orderLineSDOMap.put(dbOrderLine.getSerialNumber(), dbOrderLine);
        }
        log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew orderLineSDOMap={}", JSON.toJSONString(orderLineSDOMap));
        Date now = new Date();
        AtomicReference<String> warehouseCodeForMainOrderSet = new AtomicReference<>("");
        request.getOrderDetails().forEach(orderLineRequest -> {
            // 新增明细行
            if (StringUtils.isBlank(orderLineRequest.getLineNum())) {
                currentMaxLineNum.set(currentMaxLineNum.get() + 10);
                // 构造新增明细数据对象
                OrderLine dbOrderLine = orderLineAtomUpdateRequestToOrderLineConvert.convert(orderLineRequest);
                dbOrderLine.setStatus(SalesOrderStatusEnum.BEFORE_DELIVERY.getCode());
                dbOrderLine.setSerialNumber(String.valueOf(currentMaxLineNum.get()));
                dbOrderLine.setMainOrderId(String.valueOf(dbOrder.getId()));
                dbOrderLine.setMainOrderBizId(dbOrder.getOrderBizId());
                dbOrderLine.setOrderLineTag(dbOrder.getOrderTag());
                if (SetOrderTag.NORMAL.equals(dbOrder.getOrderTag())) {
                    dbOrderLine.setReceiveWarehouseName(null);
                    dbOrderLine.setReceiveWarehouseOutCode(null);
                    dbOrderLine.setReceiveFactoryCode(null);
                    dbOrderLine.setReceiveStockCode(null);
                    dbOrderLine.setReceiveFactoryCode(null);
                }
                dbOrderLine.setStatus(Optional.ofNullable(dbOrderLine.getStatus()).orElse(OrderStatus.BEFORE_SUBMIT.getCode()));
                dbOrderLine.setGmtCreate(now);
                dbOrderLine.setSyncVersion(0);
                dbOrderLine.setModifierId(request.getModifierCode());
                dbOrderLine.setModifierName(request.getModifierName());
                if (OrderCategoryEnum.STOCK.getCode().equals(request.getOrderCategoryCode())) {
                    dbOrderLine.setRelationLineNo(String.valueOf(currentMaxLineNum.get()));
                }
                String features = dbOrderLine.getFeatures();
                String bizFeatures = dbOrderLine.getBizFeatures();
                JSONObject jsonObject = null;
                if (StringUtils.isNotBlank(features)) {
                    jsonObject = JSONObject.parseObject(features);
                } else {
                    jsonObject = new JSONObject();
                }
                if (StringUtils.isNotBlank(bizFeatures)) {
                    JSONObject bizFeaturesJson = JSONObject.parseObject(bizFeatures);
                    String fulfillmentMsg = (String) bizFeaturesJson.get(OrderFeaturesKey.FULFILLMENT_MSG);
                    if (StringUtils.isNotBlank(fulfillmentMsg)) {
                        jsonObject.put(OrderFeaturesKey.FULFILLMENT_MSG, fulfillmentMsg);
                    }
                }
                jsonObject.put(OrderFeaturesKey.FULFILLMENT_STATUS, FulfillmentStatusEnum.BEFORE_FULFILLMENT.getCode());
                dbOrderLine.setFeatures(jsonObject.toJSONString());
                orderLinesForAdd.add(dbOrderLine);
                if (StringUtils.isNotBlank(dbOrderLine.getShippingWarehouseCode())) {
                    warehouseCodeForMainOrderSet.set(dbOrderLine.getShippingWarehouseCode());
                }
            }

            // 更新明细行
            if (StringUtils.isNotBlank(orderLineRequest.getLineNum())) {
                OrderLine dbOrderLine = orderLineSDOMap.get(orderLineRequest.getLineNum());
                // 构造更新明细数据对象
                boolean hasInfoChange = orderLineAtomUpdateRequestToOrderLineConvert.convertNew(dbOrderLine, orderLineRequest);
                if (hasInfoChange) {
                    // 如果只传了明细行号，没内容变更，则不修改修改人和时间
                    dbOrderLine.setModifierName(request.getModifierName());
                    dbOrderLine.setModifierId(request.getModifierCode());
                    dbOrderLine.setGmtModified(new Date());
                }
                orderLinesForUpdate.add(dbOrderLine);
                if (StringUtils.isNotBlank(dbOrderLine.getShippingWarehouseCode())) {
                    warehouseCodeForMainOrderSet.set(dbOrderLine.getShippingWarehouseCode());
                }
            }
        });

        // 删除子单
        List<String> updateLineSerialNumber = orderLinesForUpdate.stream().map(OrderLine::getSerialNumber).collect(Collectors.toList());
        List<Long> deleteIdList = dbOderLines.stream().filter(dbOrderLine -> !updateLineSerialNumber.contains(dbOrderLine.getSerialNumber())).map(OrderLine::getId).collect(Collectors.toList());
        log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew deleteIdList:{}; orderLinesForAdd:{}, orderLinesForUpdate:{}",
                JSON.toJSONString(deleteIdList), JSON.toJSONString(orderLinesForAdd), JSON.toJSONString(orderLinesForUpdate));
        if (CollectionUtils.isNotEmpty(deleteIdList)) {
            orderLineService.deleteByIds(DeleteByIdsRequest.builder().ids(deleteIdList).build());
        }
        // 保存新增
        if (CollectionUtils.isNotEmpty(orderLinesForAdd)) {
            orderLinesForAdd.forEach(x -> orderLineService.createOrderLine(x));
        }
        // 修改的明细
        if (CollectionUtils.isNotEmpty(orderLinesForUpdate)) {
            orderLinesForUpdate.forEach(x -> {
                log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew updateOrderLineRequest:{}", JSON.toJSONString(x));
                UpdateOrderLineResponse updateOrderLineResponse = orderLineService.updateOrderLine(x);
                log.info("SalesOrderAtomUpdateServiceImpl#submitSaveTransactionalNew updateOrderLineResponse:{}", JSON.toJSONString(updateOrderLineResponse));
            });
        }
        // 回填主单要更新的字段数据
        orderAtomUpdateRequestToOrderConvert.convertOrder(dbOrder, request);

        JSONObject features = JSON.parseObject(Optional.ofNullable(dbOrder.getFeatures()).orElse(""));
        features.put("updateLock", "true");
        // features.put("updateJson", JSON.toJSONString(request));
        dbOrder.setFeatures(features.toJSONString());
        // 发送消息通知SAP进行修改
        sendMsgService.sendMsgToSAP(JSON.toJSONString(Collections.singletonList(request)));

        // 修改人信息
        dbOrder.setModifier(request.getModifierCode());
        dbOrder.setModifierCode(request.getModifierCode());
        dbOrder.setModifierName(request.getModifierName());
        dbOrder.setModifierName2(request.getModifierName());
        dbOrder.setGmtModified(now);

        orderService.updateOrder(dbOrder);

        // 构建新建子单行号、来源单号 response
        List<OrderLineAtomCreateResponse> orderDetailList = new ArrayList<>();
        orderLinesForAdd.forEach(orderLine -> {
            orderDetailList.add(OrderLineAtomCreateResponse.builder().lineNum(orderLine.getSerialNumber()).sourceLineNum(orderLine.getSourceLineNum()).build());
        });
        response.setOrderDetails(orderDetailList);
    }

    /**
     * 校验订单
     */
    private boolean checkOrder(Order order, List<OrderLine> orderLines, OrderAtomUpdateRequest request, OrderAtomUpdateResponse response) {
        // 校验订单状态
        if (!OrderStatus.BEFORE_DELIVERY.getCode().equals(order.getStatus())) {
            response.setErrorCode("OC-01-001-01-16-053");
            response.setMessage(ErrorMessage.code("OC-01-001-01-16-053").getDisplayErrorMessage());
            return false;
        }

        // 校验明细信息
        Set<String> dbLineNumList = new HashSet<>();
        Map<String, OrderLine> orderLineMap = new HashMap<>();
        for (OrderLine orderLine : orderLines) {
            dbLineNumList.add(orderLine.getSerialNumber());
            orderLineMap.put(orderLine.getSerialNumber(), orderLine);
        }

        Set<String> requestLineNumList = new HashSet<>();
        for (OrderLineAtomUpdateRequest lineAtomUpdateRequest : request.getOrderDetails()) {
            // 修改明细
            if (StringUtils.isNotBlank(lineAtomUpdateRequest.getLineNum())) {
                String lineNumInRequest = lineAtomUpdateRequest.getLineNum();
                OrderLine orderLine = orderLineMap.get(lineNumInRequest);
                if (Objects.isNull(orderLine)) {
                    response.setErrorCode("OC-01-001-01-16-017");
                    response.setMessage(ErrorMessage.code("OC-01-001-01-16-017", lineNumInRequest).getDisplayErrorMessage());
                    return false;
                }

                // 校验订单行
                if (!OrderStatus.BEFORE_DELIVERY.getCode().equals(orderLine.getStatus())) {
                    response.setErrorCode("OC-01-001-01-16-053");
                    response.setMessage(ErrorMessage.code("OC-01-001-01-16-053").getDisplayErrorMessage());
                    return false;
                }

                requestLineNumList.add(lineNumInRequest);
                //拼接外部单号，发sap要用
                lineAtomUpdateRequest.setOutLineNum(orderLine.getOuterOrderLineId());
            }
        }
        return true;
    }
}
